﻿
#region ConvertTo-DistinguishedName 

function ConvertTo-DistinguishedName
{
    
    <#
        .Synopsis 
            Converts the Netbios or dnsname to DistinguishedName name
            
        .Description
            Converts the Netbios or dnsname to DistinguishedName name
            
        .Parameter dnsname
            dnsname to convert
            
        .Parameter Netbios
            Netbios name to convert
            
        .Example
            # Using DNS
            ConvertTo-DistinguishedName Dev.Lab
            
            # Using Netbios
            ConvertTo-DistinguishedName Dev
            
        .Output
            System.String
            
        .Link
            ConvertTo-DNSName
            ConvertTo-NetbiosName
            
        .Notes
            NAME:      ConvertTo-DistinguishedName
            AUTHOR:    YetiCentral\bshell
            Website:   www.bsonposh.com
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
    
        [ValidatePattern('^(\w|\d)+\.*')]
        [Parameter()]
        $DNSName,
        
        [Parameter()]
        $Netbios
    )
    if($DNSName)
    {
        ([ADSI]"LDAP://$DNSName").distinguishedName[0]
    }
    if($NetBios)
    {
        ([ADSI]"LDAP://$NetBios").distinguishedName[0]
    }
}
    
#endregion 


#region ConvertTo-DNSName 

function ConvertTo-DNSName
{
    <#
        .Synopsis
            Converts the Netbios or DistinguishedName to DNSName name
            
        .Description
            Converts the Netbios or DistinguishedName to DNSName name
            
        .Parameter DistinguishedName
            DistinguishedName to convert
            
        .Parameter Netbios
            Netbios name to convert
            
        .Example
            # Using DistinguishedName
            ConvertTo-DNSName "dc=corp,dc=lab"
            
            # Using Netbios
            ConvertTo-DNSName Dev
            
        .Outputs
            System.String
            
        .Link
            ConvertTo-NetBiosName
            ConvertTo-DistinguishedName
            
        .Notes
            NAME:      ConvertTo-DNSName
            AUTHOR:    YetiCentral\bshell
            Website:   www.bsonposh.com
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
        Param(
    
        [Alias('dn')]
        [ValidatePattern('^((CN|OU)=.*)*(DC=.*)*$')]
        [Parameter()]
        $DistinguishedName,
        
        [Parameter()]
        $Netbios
    )
    if($DistinguishedName)
    {
        $SplitName = $DistinguishedName -split "DC=" -replace ",",""
        $SplitName[1..$SplitName.count] -join "."
    }
    if($Netbios)
    {
        $rootDSE = [ADSI]"LDAP://$Netbios/rootDSE"
        $SplitName = $rootDSE.dnsHostName[0].Split(".")
        $SplitName[1..$SplitName.count] -join "."
    }
}
    
#endregion 


#region ConvertTo-Name 

function ConvertTo-Name
{
    param($sid)
    $ID = New-Object System.Security.Principal.SecurityIdentifier($sid)
    $User = $ID.Translate( [System.Security.Principal.NTAccount])
    $User.Value
}
    
#endregion 


#region ConvertTo-NetbiosName 

function ConvertTo-NetbiosName
{
    
    <#
        .Synopsis
            Converts the DNS or DistinguishedName to netbios name
            
        .Description
            Converts the DNS or DistinguishedName to netbios name
            
        .Parameter DistinguishedName
            DistinguishedName to Convert
            
        .Parameter DNSName
            DNSName to Convert
    
        .Example
            # Using DistinguishedName
            ConvertTo-NetbiosName "dc=Dev,dc=Lab"
            
            # Using DNSName
            ConvertTo-NetbiosName Dev.Lab
            
        .Outpus
            System.String
            
        .Link
            ConvertTo-DNSName
            ConvertTo-DistinguishedName
            
        .Notes
            NAME:      ConvertTo-NetbiosName
            AUTHOR:    YetiCentral\bshell
            Website:   www.bsonposh.com
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
    
        [Alias('dn')]
        [ValidatePattern('^((CN|OU)=.*)*(DC=.*)*$')]
        [Parameter()]
        [string]$DistinguishedName,
        
        [ValidatePattern('^(\w|\d)+\.*')]
        [Parameter()]
        [string]$DNSName
    )
    if($DistinguishedName)
    {
        ([ADSI]"LDAP://$DistinguishedName").Name
    }
    if($DNSName)
    {
        ([ADSI]"LDAP://$DNSName").Name
    }
}
    
#endregion 


#region ConvertTo-Sid 

function ConvertTo-Sid
{
    <#
        .Synopsis
            Converts the user name to SID.
            
        .Description
            Converts the KMS Return code to a friendly valueConverts the user name to SID
            
        .Parameter UserName
            UserName to convert
            
        .Parameter Domain
            Domain of the User (defaults to current domain.)
    
        .Example
            ConvertTo-SID dev\bshell
            Description
            -----------
            Converts the user name dev\bshell to sid
            
        .Outpus
            System.String
            
        .Notes
            NAME:      ConvertTo-SID
            AUTHOR:    YetiCentral\bshell
            Website:   www.bsonposh.com
            #Requires -Version 2.0
    #>
    param($UserName,$domain = $env:USERDOMAIN)
    switch -regex ($UserName)
    {
        ".*\\.*"   {
                        $ID = New-Object System.Security.Principal.NTAccount($UserName)
                }
        ".*@.*"    {
                        $ID = New-Object System.Security.Principal.NTAccount($UserName)
                }
        Default    {
                        $ID = New-Object System.Security.Principal.NTAccount($domain,$UserName)
                }
    }
    $SID = $ID.Translate([System.Security.Principal.SecurityIdentifier])
    $SID.Value
}
    
#endregion 


#region ConvertTo-UACFLag 

function ConvertTo-UACFLag 
{
    <#
        .Synopsis
            Converts the User Account Control flag to an array of strings.
            
        .Description
            Converts the User Account Control flag to an array of strings.
            
        .Parameter UAC
            User Account control flag to convert
            
        .Parameter ToString
            [Switch] :: Returns a string instead of array.
    
        .Example
            ConvertTo-UACFlag 514
            Description
            -----------
            Converts the UAC flag 514 to Array of strings
            ACCOUNTDISABLE
            NORMAL_ACCOUNT
            
        .Example
            ConvertTo-UACFlag 514 -ToString
            Description
            -----------
            Converts the UAC flag 514 to a string
            ACCOUNTDISABLE,NORMAL_ACCOUNT
            
        .Outpus
            System.Array
            
        .Notes
            NAME:      ConvertTo-UACFlag
            AUTHOR:    YetiCentral\bshell
            Website:   www.bsonposh.com
            #Requires -Version 2.0
    #>
    Param(
        [int]$uac,
        [switch]$ToString
    )
    $flags = @()
    switch ($uac)
    {
        {($uac -bor 0x0002) -eq $uac}    {$flags += "ACCOUNTDISABLE"}
        {($uac -bor 0x0008) -eq $uac}    {$flags += "HOMEDIR_REQUIRED"}
        {($uac -bor 0x0010) -eq $uac}    {$flags += "LOCKOUT"}
        {($uac -bor 0x0020) -eq $uac}    {$flags += "PASSWD_NOTREQD"}
        {($uac -bor 0x0040) -eq $uac}    {$flags += "PASSWD_CANT_CHANGE"}
        {($uac -bor 0x0080) -eq $uac}    {$flags += "ENCRYPTED_TEXT_PWD_ALLOWED"}
        {($uac -bor 0x0100) -eq $uac}    {$flags += "TEMP_DUPLICATE_ACCOUNT"}
        {($uac -bor 0x0200) -eq $uac}    {$flags += "NORMAL_ACCOUNT"}
        {($uac -bor 0x0800) -eq $uac}    {$flags += "INTERDOMAIN_TRUST_ACCOUNT"}
        {($uac -bor 0x1000) -eq $uac}    {$flags += "WORKSTATION_TRUST_ACCOUNT"}
        {($uac -bor 0x2000) -eq $uac}    {$flags += "SERVER_TRUST_ACCOUNT"}
        {($uac -bor 0x10000) -eq $uac}   {$flags += "DONT_EXPIRE_PASSWORD"}
        {($uac -bor 0x20000) -eq $uac}   {$flags += "MNS_LOGON_ACCOUNT"}
        {($uac -bor 0x40000) -eq $uac}   {$flags += "SMARTCARD_REQUIRED"}
        {($uac -bor 0x80000) -eq $uac}   {$flags += "TRUSTED_FOR_DELEGATION"}
        {($uac -bor 0x100000) -eq $uac}  {$flags += "NOT_DELEGATED"}
        {($uac -bor 0x200000) -eq $uac}  {$flags += "USE_DES_KEY_ONLY"}
        {($uac -bor 0x400000) -eq $uac}  {$flags += "DONT_REQ_PREAUTH"}
        {($uac -bor 0x800000) -eq $uac}  {$flags += "PASSWORD_EXPIRED"}
        {($uac -bor 0x1000000) -eq $uac} {$flags += "TRUSTED_TO_AUTH_FOR_DELEGATION"}
    }
    if($toString)
    {
        $flags | %{if($mystring){$mystring += ",$_"}else{$mystring = $_}};$mystring}else{$flags
    }
}
    
#endregion 


#region Get-ADACL 

function Get-ADACL
{
        
    <#
        .Synopsis 
            Gets ACL object or SDDL for AD Object
            
        .Description
            Gets ACL object or SDDL for AD Object
            
        .Parameter DistinguishedName
            DistinguishedName of the Object to Get the ACL from
            
        .Parameter SDDL [switch]
            If passed it will return the SDDL string
            
        .Example
            Get ACL for ‘cn=users,dc=corp,dc=lab’
                Get-ADACL ‘cn=users,dc=corp,dc=lab’
            Get SDDL for ‘cn=users,dc=corp,dc=lab’
                Get-ADACL ‘cn=users,dc=corp,dc=lab’ -sddl
                
        .Outputs
            Object
            
        .Link
            N/A
            
        .Notes
            NAME:      Get-ADACL
            AUTHOR:    YetiCentral\bshell
            Website:   www.bsonposh.com
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
    
        [Alias('dn')]
        [ValidatePattern('^((CN|OU)=.*)*(DC=.*)*$')]
        [Parameter(ValueFromPipeline=$true,Mandatory=$True)]
        [string]$DistinguishedName,
        
        [Parameter()]
        [switch]$SDDL
    )
    Write-Verbose " + Processing Object [$DistinguishedName]"
    $DE = [ADSI]"LDAP://$DistinguishedName"
    
    Write-Verbose "   - Getting ACL"
    $acl = $DE.psbase.ObjectSecurity
    if($SDDL)
    {
        Write-Verbose "   - Returning SDDL"
        $acl.GetSecurityDescriptorSddlForm([System.Security.AccessControl.AccessControlSections]::All)
    }
    else
    {
        Write-Verbose "   - Returning ACL Object [System.DirectoryServices.ActiveDirectoryAccessRule]"
        $acl.GetAccessRules($true,$true,[System.Security.Principal.SecurityIdentifier])
    }
}
    
#endregion 


#region Get-DCConnectionObject 

function Get-DCConnectionObject
{
        
    <#
        .Synopsis 
            Gets Active Directory Connection Objects for DCs that match the filter.
            
        .Description
            Gets Active Directory Connection Objects for DCs that match the filter.
            
        .Parameter Filter
            Regex filter for the DC(s) to get the connection Objects for.
            
        .Example
            Get-DCConnectionObject -filter "(Site1)|(site2)"
            Description
            -----------
            Gets the connection objects for DC(s) that match site1 or site2
    
        .OUTPUTS
            Object
            
        .INPUTS
            String
            
        .Link
            Get-DomainController
        
        .Notes    
            NAME:      Get-DCConnectionObject
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    Param($Filter = ".*")
    $Myforest = [DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
    $MyDCs = $Myforest.Domains | foreach-object{$_.DomainControllers} | ?{$_.name -match $Filter}
    $MyDCs | %{$_.InboundConnections}
    

}
    
#endregion 


#region Get-Domain 

function Get-Domain
{
        
    <#
        .Synopsis 
            Returns the Local Domain.
            
        .Description
            Returns the Local Domain.
            
        .Parameter DomainController
            Domain Controller to get the forest from.
        
        .Parameter Credential
            PSCredentials to use to discover forest with.
            
        .Example
            Get-Domain
            Description
            -----------
            Returns the default domain
    
        .OUTPUTS
            System.DirectoryService.ActiveDirectory.Domain
            
        .INPUTS
            System.String
            
        .Link
            Get-Forest
        
        .Notes
            NAME:      Get-Domain
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    
    Param(
    
        [Parameter()]
        $DomainController,
        
        [Parameter()]
        [Management.Automation.PSCredential]$Credential
    
    )
	
    if(!$DomainController)
    {
        [DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
        return
    }
    
    if($Creds)
    {
        $Context = new-object DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",
                                                                                $DomainController,
                                                                                $Creds.UserName,
                                                                                $Creds.GetNetworkCredential().Password)
    }
    else
    {
        $Context = new-object DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$DomainController)
    }
    
    [DirectoryServices.ActiveDirectory.Domain]::GetDomain($Context)
}
    
#endregion 


#region Get-DomainController 

function Get-DomainController
{
        
    <#
        .Synopsis 
            Returns a DomainController Object
        
        .Description
            Returns an object representation of a Domain Controller with various properties. By default it returns a single
        discovered Domain Controller.
        
        .Parameter Name
            Specifies the Name of the Domain Controller you want to get.
        
        .Parameter Filter
            A regular expression that allows you to filter the Domain Controllers to return. 
        
        .Parameter Site
            If Specified it will only return Domain Controllers from that Site
        
        .Parameter Domain
            Domain to return all Domain Controllers from.
        
        .Parameter Forest
            Forest to return all Domain Controllers from.
        
        .Parameter Target
            Source Domain Controller to use for Discovery. Valid with Filter, Domain, and Forest Parameters
        
        .Example
            Get-DomainController MyDC.domain.com
            Description
            -----------
            Get a Single Domain Controller
        
        .Example
            Get-DomainController -filter "MyDC(dc|gc)"
            Description
            -----------
            Get all Domain Controllers in the current domain that match a specific regular expression
            
        .Example
            Get-DomainController -site MySiteName
            Description
            -----------
            Get all the Domain Controllers for specified Site
            
        .Example
            Get-DomainController -domain child.domain.com
            Description
            -----------
            Get all the Domain Controllers for specified Domain
            
        .Example
            Get-DomainController -forest domain.com
            Description
            -----------
            Get all the Domain Controllers for specified Forest
        
        .Example
            Get-DomainController -domain child.domain.com -target ChildDC.child.domain.com
            Description
            -----------
            Get Domain Controllers using a specific Target
            
        .OUTPUTS
            System.DirectoryServices.ActiveDirectory.DomainController
        
        .INPUTS
            String
        
        .Link
            Get-GlobalCatalog
            Get-Domain
            Get-Forest
        
        .Notes
            NAME:      Get-DomainController
            AUTHOR:    Brandon Shell (aka BSonPosh)
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName="DCName")]
    
    Param(
        [alias("ComputerName")]
        [Parameter(ValueFromPipeline=$true,ParameterSetName="DCName",Position=0)]
        [string]$Name,
        
        [Parameter(ParameterSetName="Filter",Position=0)]
        [string]$Filter,
        
        [Parameter(ParameterSetName="Site",Position=0)]
        [string]$Site,
        
        [Parameter(ParameterSetName="Domain",Position=0)]
        [string]$Domain,
        
        [Parameter(ParameterSetName="Forest",Position=0)]
        [string]$Forest,
        
        [Parameter()]
        [string]$Target
    )
    Begin
    {
        function Get-DCByName
        {
            [CmdletBinding()]
            Param($ServerName,$PSCreds)
            Write-Verbose " [Get-DCByName] :: Called"
            if($ServerName)
            {
                Write-Verbose " [Get-DCByName] :: Getting Domain Controller by ServerName"
                Write-Verbose " [Get-DCByName] :: Getting DirectoryContext for Server: $ServerName"
                $Context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$ServerName)
                Write-Verbose " [Get-DCByName] :: DirectoryContext: $Context"
                Write-Verbose " [Get-DCByName] :: Getting Domain Controller using GetDomainController(`$Context)"
                $MyDC = [System.DirectoryServices.ActiveDirectory.DomainController]::GetDomainController($Context)
            }
            else
            {
                Write-Verbose " [Get-DCByName] :: No Server Specified. Getting Current Domain"
                Write-Verbose " [Get-DCByName] :: Getting Domain - [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()"
                $Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
                Write-Verbose " [Get-DCByName] :: Domain = $Domain"
                Write-Verbose " [Get-DCByName] :: Getting Random Domain Controller - `$Domain.FindDomainController()"
                $MyDC = $Domain.FindDomainController()
            }
            Write-Verbose " [Get-DCByName] :: Found DC: $MyDC"
            Write-Verbose " [Get-DCByFilter] :: Adding DSAGUID property"
            $MyDC | Add-Member -name "DSAGUID" -MemberType ScriptProperty -Value $GetDSAGUID -PassThru
        }
        function Get-DCByFilter
        {
            [CmdletBinding()]
            Param($Filter,$ServerName,$PSCreds)
            Write-Verbose " [Get-DCByFilter] :: Called"
            if($ServerName)
            {
                Write-Verbose " [Get-DCByFilter] :: Getting Domain by ServerName"
                Write-Verbose " [Get-DCByFilter] :: Getting DirectoryContext for Server: $ServerName"
                $Context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$ServerName)
                Write-Verbose " [Get-DCByFilter] :: DirectoryContext: $Context"
                Write-Verbose " [Get-DCByFilter] :: Getting Domain Controller using GetDomain(`$Context)"
                $Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($Context)
                Write-Verbose " [Get-DCByFilter] :: Domain = $Domain"
            }
            else
            {
                Write-Verbose " [Get-DCByFilter] :: No Server Specified. Discovering DC"
                Write-Verbose " [Get-DCByFilter] :: Getting Domain - [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()"
                $Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
                Write-Verbose " [Get-DCByFilter] :: Domain = $Domain"
            }
            Write-Verbose " [Get-DCByFilter] :: Getting Domain Controllers that match the filter - `$Domain.DomainControllers | ?{`$_.NAME -match `$Filter}"
            $DomainControllers = $Domain.DomainControllers | ?{$_.NAME -match $Filter}
            Write-Verbose " [Get-DCByFilter] :: Found [$($DomainControllers.count)] Domain Controllers"
            foreach($MyDC in $DomainControllers)
            {
                Write-Verbose " [Get-DCByFilter] :: Found DC: $MyDC"
                Write-Verbose " [Get-DCByFilter] :: Adding DSAGUID property"
                $MyDC | Add-Member -name "DSAGUID" -MemberType ScriptProperty -Value $GetDSAGUID -PassThru
            }
        }
        function Get-DCBySite
        {
            [CmdletBinding()]
            Param($SiteName,$ServerName,$PSCreds)
            Write-Verbose " [Get-DCBySite] :: Called"
            if($ServerName)
            {
                Write-Verbose " [Get-DCBySite] :: Getting Domain by ServerName"
                Write-Verbose " [Get-DCBySite] :: Getting DirectoryContext for Server: $ServerName"
                $Context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$ServerName)
                Write-Verbose " [Get-DCBySite] :: DirectoryContext: $Context"
                Write-Verbose " [Get-DCBySite] :: Getting Domain Controller using GetDomain(`$Context)"
                $Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($Context)
                Write-Verbose " [Get-DCBySite] :: Domain = $Domain"
            }
            else
            {
                Write-Verbose " [Get-DCBySite] :: No Server Specified. Discovering DC"
                Write-Verbose " [Get-DCBySite] :: Getting Domain - [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()"
                $Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
                Write-Verbose " [Get-DCBySite] :: Domain = $Domain"
            }
            
            Write-Verbose " [Get-DCBySite] :: Getting Domain Controllers in Site [$SiteName] - `$Domain.FindAllDomainControllers(`$SiteName)"
            $DomainControllers = $Domain.FindAllDomainControllers($SiteName)
            Write-Verbose " [Get-DCBySite] :: Found [$($DomainControllers.count)] Domain Controllers"
            foreach($MyDC in $DomainControllers)
            {
                Write-Verbose " [Get-DCBySite] :: Found DC: $MyDC"
                Write-Verbose " [Get-DCByFilter] :: Adding DSAGUID property"
                $MyDC | Add-Member -name "DSAGUID" -MemberType ScriptProperty -Value $GetDSAGUID -PassThru
            }
        }
        function Get-DCByDomain
        {
            [CmdletBinding()]
            Param($DomainName,$ServerName,$PSCreds)
            Write-Verbose " [Get-DCByDomain] :: Called"
            if($ServerName)
            {
                Write-Verbose " [Get-DCByDomain] :: Getting Domain by ServerName"
                Write-Verbose " [Get-DCByDomain] :: Getting DirectoryContext for Server: $ServerName"
                $Context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$ServerName)
                Write-Verbose " [Get-DCByDomain] :: DirectoryContext: $Context"
                Write-Verbose " [Get-DCByDomain] :: Getting Domain using GetDomain(`$Context)"
                $Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($Context)
            }
            else
            {
                Write-Verbose " [Get-DCByDomain] :: Getting DirectoryContext for Domain: $DomainName"
                $Context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain",$DomainName)
                Write-Verbose " [Get-DCByDomain] :: DirectoryContext: $Context"
                Write-Verbose " [Get-DCByDomain] :: Getting Domain using GetDomain(`$Context)"
                $Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($Context)
            }
            Write-Verbose " [Get-DCByDomain] :: Domain = $Domain"
            Write-Verbose " [Get-DCByDomain] :: Getting Domain Controllers in Domain [$DomainName] - `$Domain.FindAllDomainControllers()"
            $DomainControllers = $Domain.FindAllDomainControllers()
            Write-Verbose " [Get-DCByDomain] :: Found [$($DomainControllers.count)] Domain Controllers"
            foreach($MyDC in $DomainControllers)
            {
                Write-Verbose " [Get-DCByDomain] :: Found DC: $MyDC"
                Write-Verbose " [Get-DCByFilter] :: Adding DSAGUID property"
                $MyDC | Add-Member -name "DSAGUID" -MemberType ScriptProperty -Value $GetDSAGUID -PassThru
            }
        }
        function Get-DCByForest
        {
            [CmdletBinding()]
            Param($ForestName,$ServerName,$PSCreds)
            Write-Verbose " [Get-DCByForest] :: Called"
            if($ServerName)
            {
                Write-Verbose " [Get-DCByForest] :: Getting Forest by ServerName"
                Write-Verbose " [Get-DCByForest] :: Getting DirectoryContext for Server: $ServerName"
                $Context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$ServerName)
                Write-Verbose " [Get-DCByForest] :: DirectoryContext: $Context"
                Write-Verbose " [Get-DCByForest] :: Getting Forest using GetForest(`$Context)"
                $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($Context)
            }
            else
            {
                Write-Verbose " [Get-DCByForest] :: Getting DirectoryContext for Forest: $ForestName"
                $Context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("Forest",$ForestName)
                Write-Verbose " [Get-DCByForest] :: DirectoryContext: $Context"
                Write-Verbose " [Get-DCByForest] :: Getting Forest using GetForest(`$Context)"
                $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($Context)
            }
            Write-Verbose " [Get-DCByForest] :: Forest = $Forest"
            Write-Verbose " [Get-DCByForest] :: Getting Domain Controllers in Forest [$ForestName] - `$Forest.Domains | %{`$_.FindAllDomainControllers()}"
            $DomainControllers = $Forest.Domains | %{$_.FindAllDomainControllers()}
            Write-Verbose " [Get-DCByForest] :: Found [$($DomainControllers.count)] Domain Controllers"
            foreach($MyDC in $DomainControllers)
            {
                Write-Verbose " [Get-DCByForest] :: Found DC: $MyDC"
                Write-Verbose " [Get-DCByFilter] :: Adding DSAGUID property"
                $MyDC | Add-Member -name "DSAGUID" -MemberType ScriptProperty -Value $GetDSAGUID -PassThru
            }
        }
        
        Write-Verbose " [Get-DomainController] :: Creating GetDSAGUID scriptblock"
        $GetDSAGUID = {
            Write-Verbose " [Get-DSAGUID] :: Getting DSA Object for $DCObject"
            $DSA = $this.GetDirectoryEntry().Children | where-object {$_.distinguishedName -match "CN=NTDS Settings,.*"}
            Write-Verbose " [Get-DSAGUID] :: DSA Object found: $($DSA.distinguishedName)"
            Write-Verbose " [Get-DSAGUID] :: Converting ObjectGUID to Friendly GUID"
            $GUID = new-object System.Guid($DSA.ObjectGUID)
            Write-Verbose " [Get-DSAGUID] :: ObjectGUID: $($GUID.GUID)"
            $GUID.ToString()
        }
    
        Write-Verbose ""
        Write-Verbose " [Begin] :: Start BeginBlock"
        Write-Verbose " [Begin] :: Parameters Passed"
        Write-Verbose " [Begin] ::    `$Name       : $Name"
        Write-Verbose " [Begin] ::    `$Filter     : $Filter"
        Write-Verbose " [Begin] ::    `$Site       : $Site"
        Write-Verbose " [Begin] ::    `$Domain     : $Domain"
        Write-Verbose " [Begin] ::    `$Forest     : $Forest"
        Write-Verbose " [Begin] ::    `$Target     : $Target"
        
        switch ($pscmdlet.ParameterSetName)
        {
            "Filter"    {if($Target){Get-DCByFilter -Filter $Filter -ServerName $Target}else{Get-DCByFilter -Filter $Filter}}
            "Site"      {if($Target){Get-DCBySite   -Site   $Site   -ServerName $Target}else{Get-DCBySite   -Site   $Site}}
            "Domain"    {if($Target){Get-DCByDomain -Domain $Domain -ServerName $Target}else{Get-DCByDomain -Domain $Domain}}
            "Forest"    {if($Target){Get-DCByForest -Forest $Forest -ServerName $Target}else{Get-DCByForest -Forest $Forest}}
        }
        
        Write-Verbose " [Begin] :: End BeginBlock"
        Write-Verbose ""
    
    }
    
    Process 
    {
        Write-Verbose ""
        Write-Verbose " [PROCESS] :: Start ProcessBlock"
        if($pscmdlet.ParameterSetName -eq "DCName")
        {
            if($name)
            {
                Get-DCbyName -ServerName $name
            }
            else
            {
                Get-DCbyName
            }
        }
        Write-Verbose " [PROCESS] :: End ProcessBlock"
        Write-Verbose ""
    }
}
    
#endregion 


#region Get-Forest 

function Get-Forest
{
        
    <#
        .Synopsis 
            Returns the Local Forest.
            
        .Description
            Returns the Local Forest.
            
        .Parameter DomainController
            Domain Controller to get the forest from.
        
        .Parameter Credential
            PSCredentials to use to discover forest with.
            
        .Example
            Get-Forest
            Description
            -----------
            Returns the default forest
    
        .OUTPUTS
            System.DirectoryService.ActiveDirectory.Forest
            
        .INPUTS
            System.String
            
        .Link
            Get-Domain
        
        .Notes
            NAME:      Get-Forest
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    
    Param(
    
        [Parameter()]
        $DomainController,
        
        [Parameter()]
        [Management.Automation.PSCredential]$Credential
    
    )
    if(!$DomainController)
    {
        [DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        return
    }
    
    if($Creds)
    {
        $Context = new-object DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",
                                                                                $DomainController,
                                                                                $Creds.UserName,
                                                                                $Creds.GetNetworkCredential().Password)
    }
    else
    {
        $Context = new-object DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$DomainController)
    }
    [DirectoryServices.ActiveDirectory.Forest]::GetForest($Context)
}
    
#endregion 


#region Get-FSMO 

function Get-FSMO
{
        
    <#
        .Synopsis 
            Returns the Flexible Single Master Operational roles.
            
        .Description
            Returns the Flexible Single Master Operational roles.
        
        .Parameter Role
            Gets a specific role. 
            Valid values: PDCMaster, RIDMaster, InfrastructureMaster, SchemaMaster, and DomainNamingMaster.
            
        .Parameter Domain
            Domain Controller to get the forest from.
        
        .Parameter Forest
            PSCredentials to use to discover forest with.
            
        .Example
            Get-FSMO
            Description
            -----------
            Returns all the FSMO roles for the current domain and forest.
            
        .Example
            Get-FSMO -role PDCMaster
            Description
            -----------
            Returns the PDCMaster FSMO role for the current domain.
            
        .Example
            Get-FSMO -Domain
            Description
            -----------
            Returns all the FSMO roles for the current domain.
            
        .Example
            Get-FSMO -Forest
            Description
            -----------
            Returns all the FSMO roles for the current forest.
            
        .OUTPUTS
            PSCustomObject
            
        .INPUTS
            System.String
            
        .Link
            Get-Forest
            Get-Domain
        
        .Notes
            NAME:      Get-FSMO
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding(DefaultParameterSetName="Role")]
    
    Param(
    
        [Parameter(ParameterSetName="Role",Position=0)]
        [ValidateSet("PDCMaster","RIDMaster","InfrastructureMaster","SchemaMaster","DomainNamingMaster")]
        [String]$Role,
        
        [Parameter(ParameterSetName="Domain",Position=0)]
        [switch]$Domain,
        
        [Parameter(ParameterSetName="Forest",Position=0)]
        [switch]$Forest
   
    )
    
    function New-FSMORole
    {
        Param($ComputerName,$Domain,$Role)
        $myobj = @{
            ComputerName  = $ComputerName
            Domain        = $Domain
            Role          = $Role
            NetBIOSName   = $ComputerName.Split(".")[0]
        }
        $obj = New-Object PSObject -Property $myobj
        $obj.PSTypeNames.Clear()
        $obj.PSTypeNames.Add('BSonPosh.ActiveDirectory.FSMORole')
        $obj
    }
    
    switch ($pscmdlet.ParameterSetName)
    {
        "Role"      {
                        $MyDomain = Get-Domain
                        $MyForest = Get-Forest
                        switch -exact ($Role)
                        {
                            "PDCMaster"                 {
                                                             New-FSMORole -ComputerName $MyDomain.PdcRoleOwner.ToString()  `
                                                                          -Domain $MyDomain.PdcRoleOwner.Domain.ToString() `
                                                                          -Role "PDCMaster"
                                                        }
                            "RIDMaster"                 {
                                                             New-FSMORole -ComputerName $MyDomain.RidRoleOwner.ToString()  `
                                                                          -Domain $MyDomain.RidRoleOwner.Domain.ToString() `
                                                                          -Role "RIDMaster"
                                                        }
                            "InfrastructureMaster"      {
                                                             New-FSMORole -ComputerName $MyDomain.InfrastructureRoleOwner.ToString()  `
                                                                          -Domain $MyDomain.InfrastructureRoleOwner.Domain.ToString() `
                                                                          -Role "InfrastructureMaster"
                                                        }
                            "SchemaMaster"              {
                                                             New-FSMORole -ComputerName $MyDomain.SchemaRoleOwner.ToString()  `
                                                                          -Domain $MyDomain.SchemaRoleOwner.Domain.ToString() `
                                                                          -Role "SchemaMaster"
                                                        }
                            "DomainNamingMaster"        {
                                                             New-FSMORole -ComputerName $MyDomain.NamingRoleOwner.ToString()  `
                                                                          -Domain $MyDomain.NamingRoleOwner.Domain.ToString() `
                                                                          -Role "DomainNamingMaster"
                                                        }
                            Default                     {
                                                            # Domain Roles
                                                            New-FSMORole -ComputerName $MyDomain.PdcRoleOwner.ToString()  `
                                                                        -Domain $MyDomain.PdcRoleOwner.Domain.ToString() `
                                                                        -Role "PDCMaster"
                                                            New-FSMORole -ComputerName $MyDomain.RidRoleOwner.ToString()  `
                                                                        -Domain $MyDomain.RidRoleOwner.Domain.ToString() `
                                                                        -Role "RIDMaster"
                                                            New-FSMORole -ComputerName $MyDomain.InfrastructureRoleOwner.ToString()  `
                                                                        -Domain $MyDomain.InfrastructureRoleOwner.Domain.ToString() `
                                                                        -Role "InfrastructureMaster"     
                                                                        
                                                            # Forest Roles
                                                            New-FSMORole -ComputerName $MyForest.SchemaRoleOwner.ToString()  `
                                                                        -Domain $MyForest.SchemaRoleOwner.Domain.ToString() `
                                                                        -Role "SchemaMaster"
                                                            New-FSMORole -ComputerName $MyForest.NamingRoleOwner.ToString()  `
                                                                        -Domain $MyForest.NamingRoleOwner.Domain.ToString() `
                                                                        -Role "DomainNamingMaster"
                                                        }   
                        }
                    }
                    
        "Domain"    {
                        $MyDomain = Get-Domain
                        # Domain Roles
                        New-FSMORole -ComputerName $MyDomain.PdcRoleOwner.ToString()  `
                                     -Domain $MyDomain.PdcRoleOwner.Domain.ToString() `
                                     -Role "PDCMaster"
                        New-FSMORole -ComputerName $MyDomain.RidRoleOwner.ToString()  `
                                     -Domain $MyDomain.RidRoleOwner.Domain.ToString() `
                                     -Role "RIDMaster"
                        New-FSMORole -ComputerName $MyDomain.InfrastructureRoleOwner.ToString()  `
                                     -Domain $MyDomain.InfrastructureRoleOwner.Domain.ToString() `
                                     -Role "InfrastructureMaster"  
                    }
                    
        "Forest"    {
                        $MyForest = Get-Forest
                        # Forest Roles
                        New-FSMORole -ComputerName $MyForest.SchemaRoleOwner.ToString()  `
                                     -Domain $MyForest.SchemaRoleOwner.Domain.ToString() `
                                     -Role "SchemaMaster"
                        New-FSMORole -ComputerName $MyForest.NamingRoleOwner.ToString()  `
                                     -Domain $MyForest.NamingRoleOwner.Domain.ToString() `
                                     -Role "DomainNamingMaster"
                    }
    }
}
#endregion 


#region Get-GlobalCatalog 

function Get-GlobalCatalog
{
        
    <#
        .Synopsis 
            Returns a Global Catalog Object
        
        .Description
            Returns an object representation of a Global Catalog with various properties. By default it returns a single di
        scovered Global Catalog.
        
        .Parameter Name
            Specifies the Name of the Global Catalog Server you want to get.
        
        .Parameter Filter
            A regular expression that allows you to filter the Global Catalog Servers to return. 
        
        .Parameter Site
            If Specified it will only return Global Catalog Servers from that Site
        
        .Parameter Domain
            Domain to return all Global Catalog Servers from.
        
        .Parameter Forest
            Forest to return all Global Catalog Servers from.
        
        .Parameter Target
            Source Global Catalog to use for Discovery. Valid with Filter, Domain, and Forest Parameters
        
        .Example
            Get-GlobalCatalog MyGC.domain.com
            Description
            -----------
            Get a Single Global Catalog Server
            
        .Example
            Get-GlobalCatalog -filter "MyGC(dc|gc)"
            Description
            -----------
            Get all Global Catalog Servers in the current domain that match a specific regular expression
            
        .Example
            Get-GlobalCatalog -site MySiteName
            Description
            -----------
            Get all the Global Catalog Servers for specified Site
        
        .Example
            Get-GlobalCatalog -domain child.domain.com
            Description
            -----------
            Get all the Global Catalog Servers in specified Domain
            
        .Example
            Get-GlobalCatalog -forest domain.com
            Description
            -----------
            Get all the Global Catalog Servers in specified Forest
        
        .Example
            Get-GlobalCatalog -domain child.domain.com -target ChildDC.child.domain.com
            Description
            -----------
            Get Global Catalogs using a specific Target
        
        .OUTPUTS
            System.DirectoryServices.ActiveDirectory.GlobalCatalog
        
        .INPUTS
            String
        
        .Link
            Get-DomainController
            Get-Domain
            Get-Forest
        
            NAME:      Get-GlobalCatalog
            AUTHOR:    Brandon Shell (aka BSonPosh)
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
        
    [CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName="GCName")]
    
    Param(
        [alias("ComputerName")]
        [Parameter(ValueFromPipeline=$true,ParameterSetName="GCName",Position=0)]
        [string]$Name,
        [Parameter(ParameterSetName="Filter",Position=0)]
        [string]$Filter,
        [Parameter(ParameterSetName="Site",Position=0)]
        [string]$Site,
        [Parameter(ParameterSetName="Domain",Position=0)]
        [string]$Domain,
        [Parameter(ParameterSetName="Forest",Position=0)]
        [string]$Forest,
        [Parameter()]
        [string]$Target
    )
    
    Begin 
    {
        function Get-GCByName
        {
            [CmdletBinding()]
            Param($ServerName,$PSCreds)
            Write-Verbose " [Get-GCByName] :: Called"
            if($ServerName)
            {
                Write-Verbose " [Get-GCByName] :: Getting Global Catalog by ServerName"
                Write-Verbose " [Get-GCByName] :: Getting DirectoryContext for Server: $ServerName"
                $Context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$ServerName)
                Write-Verbose " [Get-GCByName] :: DirectoryContext: $Context"
                Write-Verbose " [Get-GCByName] :: Getting Global Catalog using GetGlobalCatalog(`$Context)"
                $MyGC = [System.DirectoryServices.ActiveDirectory.GlobalCatalog]::GetGlobalCatalog($Context)
            }
            else
            {
                Write-Verbose " [Get-GCByName] :: No Server Specified. Discovering DC"
                Write-Verbose " [Get-GCByName] :: Getting Domain - [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()"
                $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
                Write-Verbose " [Get-GCByName] :: Forest = $Forest"
                Write-Verbose " [Get-GCByName] :: Getting Random Global Catalog - `$Forest.FindDomainController()"
                $MyGC = $Forest.FindGlobalCatalog()
            }
            Write-Verbose " [Get-GCByName] :: Found DC: $MyGC"
            Write-Verbose " [Get-GCByName] :: Getting DSA GUID for DC"
            $MyDSAGUID = Get-DSAGUID $MyGC
            Write-Verbose " [Get-GCByName] :: Adding DSA [$MyDSAGUID] GUID to DC Object"
            $MyGC | Add-Member -name "DSAGUID" -MemberType NoteProperty -Value $MyDSAGUID -PassThru
        }
        function Get-GCByFilter
        {
            [CmdletBinding()]
            Param($Filter,$ServerName,$PSCreds)
            Write-Verbose " [Get-GCByFilter] :: Called"
            if($ServerName)
            {
                Write-Verbose " [Get-GCByFilter] :: Getting Forest by ServerName"
                Write-Verbose " [Get-GCByFilter] :: Getting DirectoryContext for Server: $ServerName"
                $Context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$ServerName)
                Write-Verbose " [Get-GCByFilter] :: DirectoryContext: $Context"
                Write-Verbose " [Get-GCByFilter] :: Getting Global Catalog using GetForest(`$Context)"
                $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($Context)
            }
            else
            {
                Write-Verbose " [Get-GCByFilter] :: No Server Specified. Getting Current Forest"
                Write-Verbose " [Get-GCByFilter] :: Getting Domain - [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()"
                $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
            }
            Write-Verbose " [Get-GCByDomain] :: Forest = $Forest"
            Write-Verbose " [Get-GCByFilter] :: Getting Global Catalogs that match the filter - `$Forest.GlobalCatalogs| ?{`$_.NAME -match `$Filter}"
            $GlobalCatalogs = $Forest.GlobalCatalogs | ?{$_.NAME -match $Filter}
            Write-Verbose " [Get-GCByFilter] :: Found [$($GlobalCatalogs.count)] Global Catalogs"
            foreach($MyGC in $GlobalCatalogs)
            {
                Write-Verbose " [Get-GCByFilter] :: Found GC: $MyGC"
                Write-Verbose " [Get-GCByFilter] :: Getting DSA GUID for GC"
                $MyDSAGUID = Get-DSAGUID $MyGC
                Write-Verbose " [Get-GCByFilter] :: Adding DSA [$MyDSAGUID] GUID to DC Object"
                $MyGC | Add-Member -name "DSAGUID" -MemberType NoteProperty -Value $MyDSAGUID -PassThru
            }
        }
        function Get-GCBySite
        {
            [CmdletBinding()]
            Param($SiteName,$ServerName,$PSCreds)
            Write-Verbose " [Get-GCBySite] :: Called"
            if($ServerName)
            {
                Write-Verbose " [Get-GCBySite] :: Getting Forest by ServerName"
                Write-Verbose " [Get-GCBySite] :: Getting DirectoryContext for Server: $ServerName"
                $Context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$ServerName)
                Write-Verbose " [Get-GCBySite] :: DirectoryContext: $Context"
                Write-Verbose " [Get-GCBySite] :: Getting Global Catalog using GetForest(`$Context)"
                $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($Context)
            }
            else
            {
                Write-Verbose " [Get-GCBySite] :: No Server Specified. Getting Current Forest"
                Write-Verbose " [Get-GCBySite] :: Getting Domain - [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()"
                $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
            }
            Write-Verbose " [Get-GCByDomain] :: Forest = $Forest"
            Write-Verbose " [Get-GCBySite] :: Getting Global Catalogs in Site [$SiteName] - `$Forest.FindAllGlobalCatalogs(`$SiteName)"
            $GlobalCatalogs = $Forest.FindAllGlobalCatalogs($SiteName)
            Write-Verbose " [Get-GCBySite] :: Found [$($GlobalCatalogs.count)] Global Catalogs"
            foreach($MyGC in $GlobalCatalogs)
            {
                Write-Verbose " [Get-GCBySite] :: Found GC: $MyGC"
                Write-Verbose " [Get-GCBySite] :: Getting DSA GUID for GC"
                $MyDSAGUID = Get-DSAGUID $MyGC
                Write-Verbose " [Get-GCBySite] :: Adding DSA [$MyDSAGUID] GUID to GC Object"
                $MyGC | Add-Member -name "DSAGUID" -MemberType NoteProperty -Value $MyDSAGUID -PassThru
            }
        }
        function Get-GCByDomain
        {
            [CmdletBinding()]
            Param($DomainName,$ServerName,$PSCreds)
            Write-Verbose " [Get-GCByDomain] :: Called"
            if($ServerName)
            {
                Write-Verbose " [Get-GCByDomain] :: Getting Forest by ServerName"
                Write-Verbose " [Get-GCByDomain] :: Getting DirectoryContext for Server: $ServerName"
                $Context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$ServerName)
                Write-Verbose " [Get-GCByDomain] :: DirectoryContext: $Context"
                Write-Verbose " [Get-GCByDomain] :: Getting Global Catalog using GetForest(`$Context)"
                $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($Context)
            }
            else
            {
                Write-Verbose " [Get-GCByDomain] :: No Server Specified. Getting Current Forest"
                Write-Verbose " [Get-GCByDomain] :: Getting Forest - [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()"
                $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
            }
            
            Write-Verbose " [Get-GCByDomain] :: Getting Global Catalogs in Domain [$DomainName] - `$Forest.FindAllGlobalCatalogs() | where{`$_.Domain.ToString() -eq `$DomainName}"
            $GlobalCatalogs = $Forest.FindAllGlobalCatalogs() | where{$_.Domain.ToString() -eq $DomainName}
            Write-Verbose " [Get-GCByDomain] :: Found [$($DomainControllers.count)] Global Catalogs"
            foreach($MyGC in $GlobalCatalogs)
            {
                Write-Verbose " [Get-GCByDomain] :: Found GC: $MyGC"
                Write-Verbose " [Get-GCByDomain] :: Getting DSA GUID for GC"
                $MyDSAGUID = Get-DSAGUID $MyGC
                Write-Verbose " [Get-GCByDomain] :: Adding DSA [$MyDSAGUID] GUID to GC Object"
                $MyGC | Add-Member -name "DSAGUID" -MemberType NoteProperty -Value $MyDSAGUID -PassThru
            }
        }
        function Get-GCByForest
        {
            [CmdletBinding()]
            Param($ForestName,$ServerName,$PSCreds)
            Write-Verbose " [Get-GCByForest] :: Called"
            if($ServerName)
            {
                Write-Verbose " [Get-GCByForest] :: Getting Forest by ServerName"
                Write-Verbose " [Get-GCByForest] :: Getting DirectoryContext for Server: $ServerName"
                $Context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$ServerName)
                Write-Verbose " [Get-GCByForest] :: DirectoryContext: $Context"
                Write-Verbose " [Get-GCByForest] :: Getting Global Catalog using GetForest(`$Context)"
                $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($Context)
            }
            else
            {
                Write-Verbose " [Get-GCByForest] :: No Server Specified. Getting Current Forest"
                Write-Verbose " [Get-GCByForest] :: Getting Domain - [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()"
                $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
            }
            Write-Verbose " [Get-GCByForest] :: Getting Global Catalogs in Domain [$DomainName] - `$Forest.FindAllGlobalCatalogs()"
            $GlobalCatalogs = $Forest.FindAllGlobalCatalogs() 
            Write-Verbose " [Get-GCByForest] :: Found [$($DomainControllers.count)] Global Catalogs"
            foreach($MyGC in $GlobalCatalogs)
            {
                Write-Verbose " [Get-GCByForest] :: Found DC: $MyGC"
                Write-Verbose " [Get-GCByForest] :: Getting DSA GUID for DC"
                $MyDSAGUID = Get-DSAGUID $MyGC
                Write-Verbose " [Get-GCByForest] :: Adding DSA [$MyDSAGUID] GUID to DC Object"
                $MyGC | Add-Member -name "DSAGUID" -MemberType NoteProperty -Value $MyDSAGUID -PassThru
            }
        }
        function Get-DSAGUID
        {
            [cmdletbinding()]
            Param($DCObject)
            Write-Verbose " [Get-DSAGUID] :: Getting DSA Object for $DCObject"
            $DSA = $DCObject.GetDirectoryEntry().Children | where-object {$_.distinguishedName -match "CN=NTDS Settings,.*"}
            Write-Verbose " [Get-DSAGUID] :: DSA Object found: $($DSA.distinguishedName)"
            Write-Verbose " [Get-DSAGUID] :: Converting ObjectGUID to Friendly GUID"
            $GUID = new-object System.Guid($DSA.ObjectGUID)
            Write-Verbose " [Get-DSAGUID] :: ObjectGUID: $($GUID.GUID)"
            $GUID.ToString()
        }
    
        Write-Verbose ""
        Write-Verbose " [Begin] :: Start BeginBlock"
        Write-Verbose " [Begin] :: Parameters Passed"
        Write-Verbose " [Begin] ::    `$Name       : $Name"
        Write-Verbose " [Begin] ::    `$Filter     : $Filter"
        Write-Verbose " [Begin] ::    `$Site       : $Site"
        Write-Verbose " [Begin] ::    `$Domain     : $Domain"
        Write-Verbose " [Begin] ::    `$Forest     : $Forest"
        Write-Verbose " [Begin] ::    `$Target     : $Target"
        
        switch ($pscmdlet.ParameterSetName)
        {
            "Filter"    {if($Target){Get-GCByFilter -Filter $Filter -ServerName $Target}else{Get-GCByFilter -Filter $Filter}}
            "Site"      {if($Target){Get-GCBySite   -Site $Site     -ServerName $Target}else{Get-GCBySite -Site $Site}}
            "Domain"    {if($Target){Get-GCByDomain -Domain $Domain -ServerName $Target}else{Get-GCByDomain -Domain $Domain}}
            "Forest"    {if($Target){Get-GCByForest -Forest $Forest -ServerName $Target}else{Get-GCByForest -Forest $Forest}}
        }
        
        Write-Verbose " [Begin] :: End BeginBlock"
        Write-Verbose ""
    
    }
    
    Process 
    {
        Write-Verbose " [PROCESS] :: Start ProcessBlock"
        if($pscmdlet.ParameterSetName -eq "GCName")
        {
            if($name)
            {
                Get-GCByName -ServerName $name
            }
            else
            {
                Get-GCByName
            }
        }
        Write-Verbose " [PROCESS] :: End ProcessBlock"
        Write-Verbose "" 
    }
}
    
#endregion 


#region Get-Schema 

function Get-Schema
{
    <#
        .Synopsis 
            Returns the Schema.
            
        .Description
            Returns the Schema.
        
        .Parameter DomainController
            Domain Controller to search on.
            
        .Parameter Credential
            Credentials to use.
            
        .Example
            Get-Schema 
            Description
            -----------
            Returnes the Schema.
            
        .Example
            Get-Schema -DomainController MyDC
            Description
            -----------
            Returnes the Schema on DC 'MyDC'
            
        .OUTPUTS
            Object
            
        .INPUTS
            System.String
            
        .Notes
            NAME:      Get-Schema
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    Param(
    
        [Parameter()]
        [String]$DomainController,
        
        [Parameter()]
        [Management.Automation.PSCredential]$Credential
    
    )
    if($DomainController -and !$Credential)
    {
        $Forest = Get-Forest -DNSName $DomainController
    }
    elseif($DomainController -and $Credential)
    {
        $Forest = Get-Forest -DNSName $DomainController -Credential $Credential
    }
    else
    {
        $Forest = Get-Forest
    }
    $Forest.Schema
}
    
#endregion 


#region Get-SchemaClass 

function Get-SchemaClass
{
        
    <#
        .Synopsis 
            Returns the Schema Class specified. 
            
        .Description
            Returns the Schema Class specified.
            
        .Parameter Class
            Class you want to return.
            
        .Parameter DomainController
            Domain Controller to search on.
            
        .Parameter Credential
            Credentials to use.
            
        .Example
            Get-SchemaClass 
            Description
            -----------
            Returnes all the Schema Classes in the Schema.
            
        .Example
            Get-SchemaClass -Class User
            Description
            -----------
            Returnes all the Schema Classes that match User.
            
        .Example
            Get-SchemaClass -DomainController MyDC
            Description
            -----------
            Returnes all the Schema Classes in the Schema on DC 'MyDC'
    
        .OUTPUTS
            Object
            
        .INPUTS
            System.String
            
        .Notes
            NAME:      Get-SchemaClass
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
        
        [Parameter()]
        [String]$Class = ".*",
        
        [Parameter()]
        [String]$DomainController,
        
        [Parameter()]
        [Management.Automation.PSCredential]$Credential
        
    )
    if($DomainController -and !$Credential)
    {
        $Forest = Get-Forest -DNSName $DomainController
    }
    elseif($DomainController -and $Credential)
    {
        $Forest = Get-Forest -DNSName $DomainController -Credential $Credential
    }
    else
    {
        $Forest = Get-Forest
    }
    
    $Forest.Schema.FindAllClasses() | ?{$_.Name -match "^$Class`$"}
}
    
#endregion 


#region Get-SchemaOID 

function Get-SchemaOID 
{
    
    <#
        .Synopsis 
            Returns any Schema Class or Property by OID.
            
        .Description
            Returns any Schema Class or Property by OID.
            
        .Parameter OID
            OID you want to search for.
            
        .Example
            Get-SchemaOID $OID
            Description
            -----------
            Returnes the Schema Class or Property associated with the OID.
    
        .OUTPUTS
            Object
            
        .INPUTS
            System.String
            
        .Notes
            NAME:      Get-SchemaOID
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    Param([String]$OID)
    $Forest = [DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
    $Forest.Schema.FindAllClasses() | ?{$_.oid -eq $OID}
    $Forest.Schema.FindAllProperties() | ?{$_.oid -eq $OID}
}
    
#endregion 


#region Get-SchemaProperty 

function Get-SchemaProperty
{
    
    <#
        .Synopsis 
            Returns the Schema Property specified. 
            
        .Description
            Returns the Schema Property specified.
            
        .Parameter Property
            Property you want to return.
            
        .Parameter DomainController
            Domain Controller to search on.
            
        .Parameter Credential
            Credentials to use.
            
        .Example
            Get-SchemaProperty 
            Description
            -----------
            Returnes all the Schema Properties in the Schema.
            
        .Example
            Get-SchemaProperty -Property name
            Description
            -----------
            Returnes all the Schema Properties that match name.
            
        .Example
            Get-SchemaProperty -DomainController MyDC
            Description
            -----------
            Returnes all the Schema Properties in the Schema on DC 'MyDC'
    
        .OUTPUTS
            Object
            
        .INPUTS
            System.String
            
        .Notes
            NAME:      Get-SchemaProperty
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
        
        [Parameter()]
        [String]$Property = ".*",
        
        [Parameter()]
        [String]$DomainController,
        
        [Parameter()]
        [Management.Automation.PSCredential]$Credential
        
    )
    
    if($DomainController -and !$Credential)
    {
        $Forest = Get-Forest -DNSName $DomainController
    }
    elseif($DomainController -and $Credential)
    {
        $Forest = Get-Forest -DNSName $DomainController -Credential $Credential
    }
    else
    {
        $Forest = Get-Forest
    }
    
    $Forest.Schema.FindAllProperties() | ?{$_.Name -match "^$Property`$"}
}
    
#endregion 


#region Get-SiteLink 

function Get-SiteLink
{
        
    <#
        .Synopsis 
            Gets site link objects
            
        .Description
            Gets site link objects from the forest.
            
        .Parameter Filter
            Returns all the sitelinks that match the filter (RegEx)
        
        .Parameter Name
            [Switch] :: Only returns the Name
            
        .Parameter Raw
            [Switch] :: Returns only Name,Cost,Options,SiteList
            
        .Parameter Full
            [Switch] :: Returns a System.DirectoryService.DirectoryEntry Object with all properties.
            
        .Example
            Get-SiteLink
            Description
            -----------
            Returns all the site links in the forest
            
        .Example
            Get-SiteLink -filter "NYC"
            Description
            -----------
            Returns all the site links in the forest with a name that matches 'NYC'
    
        .Example
            Get-SiteLink -filter "NYC" -raw -full
            Description
            -----------
            Returns a DirectoryEntry for all the site links in the forest with a name that matches 'NYC'
            
        .OUTPUTS
            PSCustomObject
            
        .INPUTS
            System.String
            
        .Notes
            NAME:      Get-SiteLink
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
        
        [Parameter()]
        $Filter=".*",
        
        [Parameter()]
        [Switch]$Name,
        
        [Parameter()]
        [Switch]$RAW,
    
        [Parameter()]
        [Switch]$Full
    )
    
    $Forest = Get-Forest
    $Sites = $forest.Sites
    $SiteLinks = $Sites | %{$_.SiteLinks} | select -Unique | ?{$_.name -match $filter}
    
    if($Raw)
    {
        if($FULL)
        {
            $SiteLInks | %{$_.GetDirectoryEntry()} 
        }
        else
        {
            $SiteLInks | %{$_.GetDirectoryEntry()} | Select Name,Cost,Options,SiteList
        }
    }
    else
    {
        if($Name)
        {
            $SiteLInks | %{$_.Name}
        }
        else
        {
            $SiteLInks | Select Name,Cost,DataCompressionEnabled,NotificationEnabled,Sites
        }
    }
}
    
#endregion 


#region Get-Site 

function Get-Site
{
        
    <#
        .Synopsis 
            Gets site objects
            
        .Description
            Gets site objects from the forest (Default Value is Computer Site.)
            
        .Parameter Filter
            Returns all the site that match the filter (RegEx)
        
        .Parameter Name
            Get site by Name
            
            
        .Example
            Get-Site
            Description
            -----------
            Returns the Site info for the local machine.
    
        .Example
            Get-SiteLink -Name "NYC" 
            Description
            -----------
            Returns "NYC" Site.
            
        .Example
            Get-SiteLink -filter "NYC" 
            Description
            -----------
            Returns all Sites that match "NYC"
            
        .OUTPUTS
            System.DirectoryServices.ActiveDirectory.ActiveDirectorySite
            
        .INPUTS
            System.String
            
        .Notes
            NAME:      Get-Site
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding(DefaultParameterSetName="ByName")]
    Param(
        
        [Parameter(ParameterSetName="ByFilter",Position=0)]
        [string]$Filter,
        
        [Parameter(ParameterSetName="ByName",Position=0)]
        [String]$Name
        
    )
    
    Write-Verbose " [Get-Site] :: Filter = $Filter"
    Write-Verbose " [Get-Site] :: Name = $Name"
    
    if($Name)
    {
        $Context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("Forest")
        [System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::FindByName($Context,$Name)
    }
    elseif($Filter)
    {
        Get-Forest | select -ExpandProperty Sites | Where-Object { $_.Name -match $Filter }
    }
    else
    {
        [System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::GetComputerSite()
    }

}
    
#endregion 


#region New-ADACE 

function New-ADACE
{
    
    <#
        .Synopsis 
            Creates a Access Control Entry to add to an AD Object
            
        .Description
            Creates a Access Control Entry to add to an AD Object
            
        .Parameter identity
            System.Security.Principal.IdentityReference
            http://msdn.microsoft.com/en-us/library/system.security.principal.ntaccount.aspx
            
        .Parameter adRights
            System.DirectoryServices.ActiveDirectoryRights
            http://msdn.microsoft.com/en-us/library/system.directoryservices.activedirectoryrights.aspx
            
        .Parameter type
            System.Security.AccessControl.AccessControlType
            http://msdn.microsoft.com/en-us/library/w4ds5h86(VS.80).aspx
            
        .Parameter GUID
        Object Type of the property
            The schema GUID of the object to which the access rule applies.
            
        .Example
            New-ADACE -id $NTIdentity -ADRights $Rights -type $type -guid "bf9679c0-0de6-11d0-a285-00aa003049e2"
            Description
            -----------
            Creates an ACE Local user with the specified permissions.
        
        .OUTPUTS
            Object
            
        .Link
            N/A
            
        .Notes
            NAME:      New-ADAce
            AUTHOR:    YetiCentral\bshell
            Website:   www.bsonposh.com
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
        [Parameter(Mandatory=$True)]
        [System.Security.Principal.IdentityReference]$identity,
        
        [Parameter(Mandatory=$True)]
        [System.DirectoryServices.ActiveDirectoryRights]$adRights,
        
        [Parameter(Mandatory=$True)]
        [System.Security.AccessControl.AccessControlType]$type,
        
        [Parameter(Mandatory=$True)]
        [string]$Guid
    )
    $ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($identity,$adRights,$type,$guid)
    $ACE
}
    
#endregion 


#region Set-ADACL 

function Set-ADACL
{
        
    <#
        .Synopsis 
            Sets the AD Object ACL to ‘ACL Object’ or ‘SDDL’ String"
            
        .Description
            Sets the AD Object ACL to ‘ACL Object’ or ‘SDDL’ String"
            
        .Parameter DistinguishedName
            DistinguishedName of the Object to Get the ACL from
            
        .Parameter ACL
            ACL Object to Apply
            
        .Parameter SDDL
            SDDL string to Apply
            
        .Example
            Set-ADACL ‘cn=users,dc=corp,dc=lab’ -ACL $acl
            Description
            -----------
            Set ACL on ‘cn=users,dc=corp,dc=lab’ using ACL Object
            
        .Example
            Set-ADACL ‘cn=users,dc=corp,dc=lab’ -sddl $mysddl
            Description
            -----------
            Set ACL on ‘cn=users,dc=corp,dc=lab’ using SDDL
                
        .OUTPUTS
            Object
            
        .Link
            N/A
            
        .Notes
            NAME:      Set-ADACL
            AUTHOR:    YetiCentral\bshell
            Website:   www.bsonposh.com
            #Requires -Version 2.0
    #>
        [cmdletbinding()]
        Param(
    
            [Alias('dn')]
            [ValidatePattern('^((CN|OU)=.*)*(DC=.*)*$')]
            [Parameter(ValueFromPipeline=$true,Mandatory=$True)]
            [string]$DistinguishedName,
            
            [Parameter()]
            [System.DirectoryServices.ActiveDirectoryAccessRule]$ACL,
            
            [Parameter()]
            [String]$SDDL,
    
        [Parameter()]
        [switch]$Replace
        )
    Write-Verbose " + Processing Object [$DistinguishedName]"
    
    $DE = [ADSI]"LDAP://$DistinguishedName"
    if($sddl)
    {
        Write-Verbose "   - Setting ACL using SDDL [$sddl]"
        $DE.psbase.ObjectSecurity.SetSecurityDescriptorSddlForm($sddl)
    }
    else
    {
        foreach($ace in $acl)
        {
            Write-Verbose "   - Adding Permission [$($ace.ActiveDirectoryRights)] to [$($ace.IdentityReference)]"
        if($Replace)
        {
            $DE.psbase.ObjectSecurity.SetAccessRule($ace)
            }
            else
            {
            $DE.psbase.ObjectSecurity.AddAccessRule($ace)             
            }
        }
    }
    $DE.psbase.commitchanges()
}
    
#endregion 


#region Test-ADReplication 

function Test-ADReplication 
{
        
    <#
        .Synopsis 
            Test Active Directory Replication Convergance
            
        .Description
            Test Active Directory Replication Convergance
            
        .Parameter Target
            dnsname of host to orginate change 
            
        .Parameter ADObject
            OU/Container/Object to set wWWHomePage attribute
        
        .Parameter Site
            Site to Limit check on
        
        .Parameter Revert
            If Passed the wWWHomePage will be reverted back
        
        .Parameter Table
            Switch to return a table or not
            
        .Example
            Test-ADReplication
            Description
            -----------
            Starts AD replication Test
            
        .Outputs
            System.String
            
        .Link
            Get-Help
            
        .Notes
            NAME:      Test-ADReplication
            AUTHOR:    YetiCentral\bshell
            Website:   www.bsonposh.com
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
        [Parameter()]
        [String]$Target = (([ADSI]"LDAP://rootDSE").dnshostname),
    
        [Parameter()]
        [String]$ADObject = ("cn=users," + ([ADSI]"").distinguishedname),
        
        [Parameter()]
        [String]$Site,
        
        [Parameter()]
        [Switch]$Revert,
    
        [Parameter()]
        [switch]$Table
    )
    function Ping-Server 
    {
    Param([string]$server)
    $pingresult = Get-WmiObject win32_pingstatus -f "address='$Server' and Timeout=1000"
    if($pingresult.statuscode -eq 0) {$true} else {$false}
    }
    
    Write-Verbose "[MAIN] :: Getting Current Domain"
    $domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
    
    if($site)
    {
        Write-Verbose "[MAIN] :: Getting Domain Controllers for Site [$Site]"
        $dclist = $domain.FindAllDomainControllers($Site)
    }
    else
    {
        Write-Verbose "[MAIN] :: Getting All Domain Controllers"
        $dclist = $domain.FindAllDomainControllers()
    }
    
    if($Table)
    {
        Write-Verbose "[MAIN] :: `$Table passed. Building Custom Object Array"
        $DCTable = @()
        $myobj = "" | select Name,Time
        $myobj.Name = ("$Target [SOURCE]").ToUpper()
        $myobj.Time = 0.00
        $DCTable += $myobj
    }
    
    $Timestamp = [datetime]::Now.ToFileTime().ToString()
    Write-Host "`n  Modifying wwwHomePage Attribute"
    Write-Host "  Object: [$ADObject]"
    Write-Host "  Target: [$Target]"
    Write-Host "  Value:  [$Timestamp]"
    
    Write-Verbose "[MAIN] :: `$MyObject = ([ADSI]`"LDAP://$Target/$ADObject`")"
    $MyObject = ([ADSI]"LDAP://$Target/$ADObject")
    
    Write-Verbose "[MAIN] :: Checking for existing wWWHomePage"
    if($MyObject.wWWHomePage)
    {
        $wwwHomePage = $MyObject.wWWHomePage
        Write-Verbose "[MAIN] :: wWWHomePage found with Value [$wwwHomePage]"
    }
    
    Write-Verbose "[MAIN] :: Setting wWWHomePage to $TimeStamp"
    $MyObject.wWWHomePage = $TimeStamp
    $MyObject.SetInfo()
    
    $dn = $MyObject.distinguishedname
    Write-Host "  Object  [$dn] Modified! `n"
    
    $start = Get-Date
    
    $i = 0
    
    Write-Host "  Found [$($dclist.count)] Domain Controllers"
    $cont = $true
    
    While($cont)
    {
        $i++
        $oldpos = $host.UI.RawUI.CursorPosition
        Write-Host "  =========== Check $i ===========" -fore white
        start-Sleep 1
        $replicated = $true
        foreach($dc in $dclist)
        {
            if($target -match $dc.Name){continue}
            if(ping-server $dc.Name)
            {
                $object = [ADSI]"LDAP://$($dc.Name)/$dn"
                if($object.wwwHomePage -eq $timeStamp)
                {
                    Write-Host "  - $($dc.Name.ToUpper()) Has Object description [$dn]" (" "*5) -fore Green
                    if($table -and !($dctable | ?{$_.Name -match $dc.Name}))
                    {
                        $myobj = "" | Select-Object Name,Time
                        $myobj.Name = ($dc.Name).ToUpper()
                        $myobj.Time = ("{0:n2}" -f ((Get-Date)-$start).TotalSeconds)
                        $dctable += $myobj
                    }
                }
                else{Write-Host "  ! $($dc.Name.ToUpper()) Missing Object [$dn]" -fore Red;$replicated  = $false}
            }
            else
            {
                Write-Host "  ! $($dc.Name.ToUpper()) Failed PING" -fore Red
                if($table -and !($dctable | ?{$_.Name -match $dc.Name}))
                {
                    $myobj = "" | Select-Object Name,Time
                    $myobj.Name = ($dc.Name).ToUpper()
                    $myobj.Time = "N/A"
                    $dctable += $myobj
                }
            }
        }
        if($replicated){$cont = $false}else{$host.UI.RawUI.CursorPosition = $oldpos}
    }
    
    $end = Get-Date
    $duration = "{0:n2}" -f ($end.Subtract($start).TotalSeconds)
    
    Write-Verbose "[MAIN] :: Checking for `$Revert"
    if($Revert)
    {
        Write-Verbose "[MAIN] :: `$Revert Switch passed"
        Write-Verbose "[MAIN] :: Getting Object to set wWWHomePage"
        Write-Verbose "[MAIN] :: `$MyObject = ([ADSI]`"LDAP://$Target/$ADObject`")"
        $MyObject = ([ADSI]"LDAP://$Target/$ADObject")
        if($wwwHomePage)
        {
            Write-Verbose "[MAIN] :: Setting Value to $wwwHomePage"
            $MyObject.wWWHomePage = $wwwHomePage
        }
        else
        {
            Write-Verbose "[MAIN] :: Clearing wWWHomePage"
            $MyObject.PutEx(1,"wWWHomePage",$null)
        }
        Write-Verbose "[MAIN] :: `$MyObject.SetInfo()"
        $MyObject.SetInfo()
    }
    Write-Host "`n    Took $duration Seconds `n" -fore Yellow
    
    
    if($table){$dctable | Sort-Object Time | Format-Table -auto}
}
    
#endregion 


#region Test-LdapFilter 

function Test-LdapFilter
{
        
    <#
        .Synopsis 
            Returns LDAP stats for an LDAP Query
        
        .Description
            Returns LDAP stats for an LDAP Query
            
        .Parameter LdapFilter
            Ldapfilter to test. Defaults to (objectclass=*).
            
        .Parameter Base
            OU or Container to start the search. Default is Domain.
        
        .Parameter Server
            Domain Controller to target the query against
            
        .Parameter PageSize
            Pagesize for the query. Default 1000
            
        .Parameter Properties
            Properties to return. Default is just DN.
        
        .Parameter Scope
            Scope of the query. Default is subtree.
            Valid Values
            - Base : Only Base level Query
            - OneLevel : Base level plus 1 level below
            - Subtree : All levels starting at base
            
        .Example
            Test-LDAPFilter "(ObjectClass=user)"
            Description
            -----------
            Get stats for specific filter returning only DN
            
        .Example
            Test-LDAPFilter "(ObjectClass=user)" -properties "sAMAccountName","lastLogon"
            Description
            -----------
            Get stats for specific filter returning sAMAccountName,lastLogon
            
        .Example
            Test-LDAPFilter "(ObjectClass=user)" -server myDC1
            Description
            -----------
            Get stats for specific filter using specific Server
            
        .Example
            Test-LDAPFilter "(ObjectClass=user)" -base "OU=MyUsers,DC=MY,DC=Domain"
            Description
            -----------
            Get stats for specific filter using specific base
            
            
        .OUTPUTS
            PSCustomObject
    
        .Notes
            NAME:      Test-LDAPFilter
            AUTHOR:    YetiCentral\bshell
            Website:   www.bsonposh.com
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
    
        [alias("filter")]
        [parameter()]    
        [string]$LdapFilter = "(objectclass=*)",
        
        [parameter()]
        [string]$base,
        
        [parameter()]
        [string]$Server,
        
        [parameter()]
        [int]$pageSize = 1000,
        
        [parameter()]
        [string[]]$Properties = @("1.1"),
        
        [parameter()]
        [string]$Scope
        
    )
    function CreateStatsObject2008
    {
        Param($StatsArray)
        $DecodedArray = [System.DirectoryServices.Protocols.BerConverter]::Decode("{iiiiiiiiiaiaiiiiiiiiiiiiii}",$StatsArray) # Win2008
        $myStatsObject = New-Object System.Object
        $myStatsObject | Add-Member -Name "ThreadCount"     -Value $DecodedArray[1]  -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "CallTime"        -Value $DecodedArray[3]  -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "EntriesReturned" -Value $DecodedArray[5]  -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "EntriesVisited"  -Value $DecodedArray[7]  -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "Filter"          -Value $DecodedArray[9]  -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "Index"           -Value $DecodedArray[11] -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "PagesReferenced" -Value $DecodedArray[13] -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "PagesRead"       -Value $DecodedArray[15] -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "PagesPreread"    -Value $DecodedArray[17] -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "PagesDirtied"    -Value $DecodedArray[19] -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "PagesRedirtied"  -Value $DecodedArray[21] -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "LogRecordCount"  -Value $DecodedArray[23] -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "LogRecordBytes"  -Value $DecodedArray[25] -MemberType "NoteProperty"
        $myStatsObject
    }
    function CreateStatsObject2003
    {
        Param($StatsArray)
        $DecodedArray = [System.DirectoryServices.Protocols.BerConverter]::Decode("{iiiiiiiiiaia}",$StatsArray) # Win2003
        $myStatsObject = New-Object System.Object
        $myStatsObject | Add-Member -Name "ThreadCount"     -Value $DecodedArray[1]  -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "CallTime"        -Value $DecodedArray[3]  -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "EntriesReturned" -Value $DecodedArray[5]  -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "EntriesVisited"  -Value $DecodedArray[7]  -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "Filter"          -Value $DecodedArray[9]  -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "Index"           -Value $DecodedArray[11] -MemberType "NoteProperty"
        $myStatsObject
    }
    function CreateStatsObject2000
    {
        Param($StatsArray)
        $DecodedArray = [System.DirectoryServices.Protocols.BerConverter]::Decode("{iiiiiiii}",$StatsArray) # Win2000
        $myStatsObject = New-Object System.Object
        $myStatsObject | Add-Member -Name "ThreadCount"          -Value $DecodedArray[1]  -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "CoreTime"             -Value $DecodedArray[3]  -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "CallTime"             -Value $DecodedArray[5]  -MemberType "NoteProperty"
        $myStatsObject | Add-Member -Name "searchSubOperations"  -Value $DecodedArray[7]  -MemberType "NoteProperty"
        $myStatsObject
    }
    
    Write-Verbose " - Loading System.DirectoryServices.Protocols"
    [VOID][System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols") 
        
    [int]$pageCount = 0
    [int]$objcount = 0
    
    $rootDSE = [ADSI]"LDAP://rootDSE"
    if(!$base)
    {
        $base = $rootDSE.defaultNamingContext
    }
    
    if(!$Server)
    {      
        $Server = $rootDSE.dnsHostName
    }
    
    switch ($rootDSE.domainControllerFunctionality)
    {
        0 {$expression = 'CreateStatsObject2000 $stats'}
        2 {$expression = 'CreateStatsObject2003 $stats'}
        3 {$expression = 'CreateStatsObject2008 $stats'}
    }
    
    Write-Verbose " - Creating LDAP connection Object"
    $connection = New-Object System.DirectoryServices.Protocols.LdapConnection($Server)
    
    switch -exact ($Scope)
    {
        "base"       {$MyScope = [System.DirectoryServices.Protocols.SearchScope]"Base"}
        "onelevel"   {$MyScope = [System.DirectoryServices.Protocols.SearchScope]"OneLevel"}
        default      {$MyScope = [System.DirectoryServices.Protocols.SearchScope]"Subtree"}
    }
    
    
    Write-Verbose " - Using Server:  [$Server]"
    Write-Verbose " - Using Base:    [$base]"
    Write-Verbose " - Scope:         [$MyScope]"
    Write-Verbose " - Using Filter:  [$filter]"
    Write-Verbose " - Page Size:     [$PageSize]"
    Write-Verbose " - Returning:     [$props]"
    Write-Verbose " - Expression:    [$expression]"
    
    Write-Verbose " + Creating SearchRequest Object"
    $SearchRequest = New-Object System.DirectoryServices.Protocols.SearchRequest($base,$Ldapfilter,$MyScope,$Properties
    )
    
    Write-Verbose "   - Creating System.DirectoryServices.Protocols.PageResultRequestControl Object"
    $PagedRequest  = New-Object System.DirectoryServices.Protocols.PageResultRequestControl($pageSize)
    
    Write-Verbose "   - Creating System.DirectoryServices.Protocols.SearchOptionsControl Object"
    $SearchOptions = New-Object System.DirectoryServices.Protocols.SearchOptionsControl([System.DirectoryServices.Protocols.SearchOption]::DomainScope)
    
    Write-Verbose "   - Creating System.DirectoryServices.Protocols.DirectoryControl Control for OID: [1.2.840.113556.1.4.970]"
    $oid = "1.2.840.113556.1.4.970"
    $StatsControl = New-Object System.DirectoryServices.Protocols.DirectoryControl($oid,$null,$false,$true)
    
    Write-Verbose "   - Adding Controls"
    [void]$SearchRequest.Controls.add($pagedRequest)
    [void]$SearchRequest.Controls.Add($searchOptions)
    [void]$SearchRequest.Controls.Add($StatsControl)
    
    $start = Get-Date
    
    while ($True)
    {
        # Increment the pageCount by 1
        $pageCount++
    
        # Cast the directory response into a SearchResponse object
        Write-Verbose " - Cast the directory response into a SearchResponse object"
        $searchResponse = $connection.SendRequest($searchRequest)
    
        # Display the retrieved page number and the number of directory entries in the retrieved page
        Write-Verbose (" - Page:{0} Contains {1} response entries" -f $pageCount,$searchResponse.entries.count)
    
        Write-Verbose " - Returning Stats for Page:$PageCount"
        $stats = $searchResponse.Controls[0].GetValue()
        $ResultStats = invoke-Expression $expression
        if($pageCount -eq 1)
        {
            $StatsFilter = $ResultStats.Filter
            $StatsIndex = $ResultStats.Index
            Write-Verbose "   + Setting Filter to [$StatsFilter]"
            Write-Verbose "   + Setting Index  to [$StatsIndex]"
        }
        
        # If Cookie Length is 0, there are no more pages to request"
        if ($searchResponse.Controls[1].Cookie.Length -eq 0)
        {
            "`nStatistics"
            "================================="
            "Elapsed Time: {0} (ms)" -f ((Get-Date).Subtract($start).TotalMilliseconds)
            "Returned {0} entries of {1} visited - ({2})`n" -f $ResultStats.EntriesReturned,$ResultStats.EntriesVisited,($ResultStats.EntriesReturned/$ResultStats.EntriesVisited).ToString('p')
            "Used Filter:"
            "- {0}`n" -f $StatsFilter
            "Used Indices:"
            "- {0}`n" -f $StatsIndex
            break
        }
    
        # Set the cookie of the pageRequest equal to the cookie of the pageResponse to request the next 
        # page of data in the send request and cast the directory control into a PageResultResponseControl object
        Write-Verbose " - Setting Cookie on SearchResponse to the PageReQuest"
        $pagedRequest.Cookie = $searchResponse.Controls[1].Cookie
    }
}
    
#endregion 


#region Trace-LDAP 

function Trace-LDAP
{
    
    Param($file = ".\ldap.etl",
          $flag = "x1FFFDFF3",
          $guid = "LDAP",
          $SessionName = "mytrace",
          $exe,
          [switch]$start,
          [switch]$ADSI,
          [switch]$LDAP
    )
    if(Test-Path $pwd\tracelog.exe)
    {
        $tracelog = "$pwd\tracelog.exe"
    }
    elseif(get-command tracelog.exe)
    {
        $tracelog = "tracelog.exe"
    }
    else
    {
        throw "Missing tracelog.exe"
        return 1
    }
    
    switch -exact ($guid)
    {
        "LDAP"  {$myguid = "`#099614a5-5dd7-4788-8bc9-e29f43db28fc"}
        "ADSI"  {$myguid = "`#7288c9f8-d63c-4932-a345-89d6b060174d"}
        Default {$myguid = $_}
    }

    Write-Host

    if($start)
    {
        Write-Host " Action: Start" -fore Yellow
        Write-Host " GUID:   $GUID" -fore Yellow
        Write-Host " File:   $file" -fore Yellow
        Write-Host " Flag:   $flag" -fore Yellow
        if($exe){Write-Host " Exe:    $exe" -fore Yellow}
        
    }
    else
    {
        Write-Host " State: Disabled" -fore Red
    }

    Write-Host

    if(!(test-Path "HKLM:\System\CurrentControlSet\Services\ldap\tracing\$exe") -and $exe)
    {
        new-Item -path "HKLM:\System\CurrentControlSet\Services\ldap\tracing" -name $exe | out-Null
    }

    if($start)
    {
        $cmd = "$tracelog -start '$SessionName' -f $file -flag $flag -guid $myguid"
    }
    else
    {
        $cmd = "$tracelog -stop $SessionName"
    }

    Write-Host
    Write-Host "==========================" -fore White -back black
    write-Host "Running Command:" -fore White
    Write-Host " ==> $cmd" -fore Yellow
    invoke-Expression $cmd 
    Write-Host "==========================" -fore White -back black
    Write-Host


}
    
#endregion 

